package com.swak.http.builder;

import static org.asynchttpclient.util.HttpConstants.Methods.GET;

import java.nio.charset.Charset;
import java.util.concurrent.CompletableFuture;

import org.asynchttpclient.AsyncCompletionHandler;
import org.asynchttpclient.AsyncCompletionHandlerBase;
import org.asynchttpclient.AsyncHttpClient;
import org.asynchttpclient.RequestBuilderBase;

import com.swak.http.handler.AbstractResponse;
import com.swak.http.handler.JsonResponse;
import com.swak.http.handler.PlainResponse;
import com.swak.http.handler.TextResponse;
import com.swak.http.handler.XmlResponse;
import com.swak.http.retry.RetryService;
import com.swak.incrementer.UUIdGenerator;
import com.swak.utils.StringUtils;

import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpMethod;

/**
 * 构建请求，并执行
 * 
 * @author lifeng
 */
public class RequestBuilder extends RequestBuilderBase<RequestBuilder> {

	/**
	 * 响应处理器
	 */
	private AsyncCompletionHandler<?> handler;

	/**
	 * 使用的客户端
	 */
	private AsyncHttpClient client;

	/**
	 * 重试次数
	 */
	private int retryTimes = 0;

	/**
	 * 请求的ID
	 */
	private final String id;

	/**
	 * 重试服务
	 */
	private RetryService retryService;

	public RequestBuilder(AsyncHttpClient client) {
		super(GET, false);
		this.id = UUIdGenerator.uuid();
		this.client = client;
	}

	public RequestBuilder(AsyncHttpClient client, RetryService retryService) {
		super(GET, false);
		this.id = UUIdGenerator.uuid();
		this.client = client;
		this.retryService = retryService;
	}

	public String getId() {
		return id;
	}

	public int getRetryTimes() {
		return retryTimes;
	}

	public RequestBuilder setRetryTimes(int retryTimes) {
		this.retryTimes = retryTimes;
		return this;
	}

	// ********* 请求方式 *************
	public RequestBuilder post() {
		this.setMethod(HttpMethod.POST.name());
		return this;
	}

	public RequestBuilder postJson() {
		this.setMethod(HttpMethod.POST.name());
		this.setHeader(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
		return this;
	}

	public RequestBuilder postXml() {
		this.setMethod(HttpMethod.POST.name());
		this.setHeader(HttpHeaderNames.CONTENT_TYPE, "application/xml; charset=UTF-8");
		return this;
	}

	public RequestBuilder get() {
		this.setMethod(HttpMethod.GET.name());
		return this;
	}

	public RequestBuilder method(HttpMethod method) {
		this.setMethod(method.name());
		return this;
	}

	// ********* 请求数据类型 *************
	public RequestBuilder jsonBody(String json) {
		this.setHeader(HttpHeaderNames.CONTENT_TYPE, "application/json; charset=UTF-8");
		this.setBody(StringUtils.getBytesUtf8(json));
		return this;
	}

	public RequestBuilder xmlBody(String xml) {
		this.setHeader(HttpHeaderNames.CONTENT_TYPE, "application/xml; charset=UTF-8");
		this.setBody(StringUtils.getBytesUtf8(xml));
		return this;
	}

	// ********* 响应处理方式 *************
	public <T> RequestBuilder jsonResult(Class<T> clazz) {
		handler = JsonResponse.create(clazz);
		return this;
	}

	public <T> RequestBuilder xmlResult(Class<T> clazz) {
		handler = XmlResponse.create(clazz);
		return this;
	}

	public RequestBuilder textResult() {
		handler = TextResponse.create();
		return this;
	}

	public RequestBuilder plainResult() {
		handler = PlainResponse.create();
		return this;
	}

	public RequestBuilder resultHandler(AsyncCompletionHandler<?> handler) {
		this.handler = handler;
		return this;
	}

	@SuppressWarnings("unchecked")
	public <T> RequestBuilder charset(Charset charset) {
		if (handler != null && handler instanceof AbstractResponse) {
			((AbstractResponse<T>) handler).use(charset);
		}
		return this;
	}

	// 获得响应处理
	private AsyncCompletionHandler<?> getHandler() {
		return this.handler == null ? new AsyncCompletionHandlerBase() : this.handler;
	}

	// ********* 执行处理 *************
	public <T> CompletableFuture<T> future(AsyncCompletionHandler<T> handler) {
		return this.resultHandler(handler).future();
	}

	public <T> CompletableFuture<T> future() {
		if (this.retryService != null && this.retryTimes > 0) {
			return this.retryService.add(new PendingConfirm().setId(id).setRetryTimes(retryTimes).setCall(() -> {
				return this.toFuture();
			}));
		}
		return this.toFuture();
	}

	@SuppressWarnings("unchecked")
	private <T> CompletableFuture<T> toFuture() {
		return (CompletableFuture<T>) getClient().executeRequest(build(), getHandler()).toCompletableFuture();
	}

	/**
	 * 默认使用设置的客户端
	 * 
	 * @return
	 */
	private AsyncHttpClient getClient() {
		return client;
	}

	/**
	 * 创建一个builder
	 * 
	 * @return
	 */
	public static RequestBuilder client(AsyncHttpClient client) {
		return new RequestBuilder(client);
	}
}
